package com.aiwu;

import android.annotation.SuppressLint;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import android.text.InputFilter;
import android.text.InputType;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.text.method.DigitsKeyListener;
import android.view.View;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;

import com.aiwu.library.util.DialogUtil;
import com.aiwu.library.util.ThreadPoolManager;
import com.aiwu.library.util.ToastUtil;

import org.citra.citra_emu.CitraApplication;
import org.citra.citra_emu.NativeLibrary;
import org.citra.citra_emu.R;

import java.util.Locale;
import java.util.regex.Pattern;

/**
 * 局域网对战
 */
public class NetPlayManager {
    /**
     * Regex of ip address.
     */
    private static final String REGEX_IP = "((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)";
    private static final String REGEX_NAME_INPUT = "[0-9a-zA-Z]*";
    private static final String REGEX_IP_INPUT = "[0-9\\.]*";
    private volatile static NetPlayManager instance;

    private AlertDialog connectToRoomDialog;
    private AlertDialog netPlayDialog;

    public static NetPlayManager getInstance() {
        if (instance == null) {
            synchronized (NetPlayManager.class) {
                if (instance == null) {
                    instance = new NetPlayManager();
                }
            }
        }
        return instance;
    }

    private NetPlayManager() {
    }

    /**
     * 连接到房间结束
     *
     * @param connected
     * @param error
     */
    public void stateChanged(boolean connected, @Nullable NativeLibrary.NetPlayError error) {
        CitraApplication.getMainHandler().post(() -> switchConnectedRoomLoading(false));
        if (connected) {
            //连接房间成功
            CitraApplication.getMainHandler().post(() -> {
                ToastUtil.toast(R.string.fight_connect_to_room_success);
                if (connectToRoomDialog != null) {
                    connectToRoomDialog.dismiss();
                }
                if (netPlayDialog != null) {
                    netPlayDialog.dismiss();
                }
            });
        } else {
            //连接房间失败
            CitraApplication.getMainHandler().post(() -> {
                ToastUtil.toast(CitraApplication.getAppContext().getString(R.string.fight_connect_to_room_error, getErrorStr(error)));
            });
        }
    }

    public static String getErrorStr(@Nullable NativeLibrary.NetPlayError error) {
        if (error == null) {
            return "";
        }
        switch (error) {
            case LostConnection:
                return "与房间的连接断开。";
            case HostKicked:
                return "你已被房主踢出房间。";
            case NameCollision:
                return "用户名已存在或无效。";
            case MacCollision:
                return "MAC 地址已经被使用。请选择其他 MAC 地址。";
            case ConsoleIdCollision:
                return "你的设备ID与房间中的另一玩家冲突了";
            case WrongVersion:
                return "版本不匹配！";
            case WrongPassword:
                return "密码错误。";
            case CouldNotConnect:
                return "无法连接到服务器。请检查连接设置是否正确。";
            case RoomIsFull:
                return "房间已满，无法连接到房间。";
            case HostBanned:
                return "这个房间的房主把你封禁了。请跟联系房主取消封禁或者尝试加入别的房间。";
            case PermissionDenied:
                return "你没有权限进行该操作。";
            case NoSuchUser:
                return "未找到你想要踢出/封禁的用户。\n该用户可能已经离开了房间。";
            default:
            case UnknownError:
                return "未知错误。";
        }
    }

    /**
     * 切换连接到房间的加载状态
     *
     * @param show
     */
    private void switchConnectedRoomLoading(boolean show) {
        if (connectToRoomDialog == null || !connectToRoomDialog.isShowing()) {
            return;
        }
        final View loadingView = connectToRoomDialog.findViewById(R.id.layout_loading);
        final ImageView ivLoading = connectToRoomDialog.findViewById(R.id.iv_loading);
        if (show) {
            connectToRoomDialog.setCancelable(false);
            loadingView.setVisibility(View.VISIBLE);
            ivLoading.startAnimation(AnimationUtils.loadAnimation(connectToRoomDialog.getContext(), com.aiwu.R.anim.loading_anim));
        } else {
            connectToRoomDialog.setCancelable(true);
            loadingView.setVisibility(View.GONE);
            ivLoading.clearAnimation();
        }
    }

    /**
     * 弹窗：局域网对战
     *
     * @param context
     */
    public static void showNetPlayDialog(final Context context) {
        final AlertDialog netPlayDialog = getInstance().netPlayDialog = new AlertDialog.Builder(context, R.style.AiWuDialog)
                .setCancelable(true)
                .setView(R.layout.dialog_fight)
                .show();
        netPlayDialog.setOnDismissListener(dialog -> getInstance().netPlayDialog = null);
        DialogUtil.setDialog(netPlayDialog, 0.5f, 0.0f, 0.8f, 0.0f);

        View createRoomView = netPlayDialog.findViewById(R.id.layout_create_room);
        TextView tvCreateRoom = netPlayDialog.findViewById(R.id.tv_create_room);
        tvCreateRoom.setText(NativeLibrary.NetPlayIsHostedRoom() ? R.string.fight_get_room_ip : R.string.fight_create_room);
        createRoomView.setOnClickListener(v -> {
            if (!isWifiConnected()) {
                ToastUtil.toast(R.string.fight_wifi_not_connect);
                return;
            }
            if (NativeLibrary.NetPlayIsHostedRoom()) {
                //查看房间IP
                DialogUtil.showSingleTip(context, context.getString(R.string.fight_room_ip, getIpAddressByWifi()));
            } else {
                //创建房间
                showCreateRoomDialog(context, netPlayDialog);
            }
        });
        createRoomView.setVisibility(!NativeLibrary.NetPlayIsHostedRoom() && NativeLibrary.NetPlayIsConnectedRoom() ? View.GONE : View.VISIBLE);

        View connectToRoomView = netPlayDialog.findViewById(R.id.layout_connect_to_room);
        connectToRoomView.setOnClickListener(v -> {
            if (!isWifiConnected()) {
                ToastUtil.toast(R.string.fight_wifi_not_connect);
                return;
            }
            if (NativeLibrary.NetPlayIsConnectedRoom()) {
                DialogUtil.showTip(context, R.string.fight_connect_to_room_tip, v1 -> {
                    showConnectToRoomDialog(context);
                }, null);
                return;
            }
            showConnectToRoomDialog(context);
        });

        View leaveRoomView = netPlayDialog.findViewById(R.id.layout_leave_room);
        leaveRoomView.setOnClickListener(v -> {
            if (!NativeLibrary.NetPlayIsConnectedRoom()) {
                netPlayDialog.dismiss();
                return;
            }
            DialogUtil.showTip(context, NativeLibrary.NetPlayIsHostedRoom() ? R.string.fight_leave_room_host_tip : R.string.fight_leave_room_member_tip, v12 -> {
                netPlayDialog.dismiss();
                NativeLibrary.NetPlayLeaveRoom();
                ToastUtil.toast(R.string.fight_leave_room_success);
            }, null);
        });
        leaveRoomView.setVisibility(NativeLibrary.NetPlayIsConnectedRoom() ? View.VISIBLE : View.GONE);
    }

    /**
     * 弹窗：创建房间
     */
    private static void showCreateRoomDialog(final Context context, final AlertDialog netPlayDialog) {
        final AlertDialog dialog = new AlertDialog.Builder(context, R.style.AiWuDialog)
                .setCancelable(true)
                .setView(R.layout.dialog_fight_room)
                .show();
        DialogUtil.setDialog(dialog, 0.45f, 0.0f, 0.75f, 0.0f);

        TextView tvTitle = dialog.findViewById(R.id.tv_title);
        tvTitle.setText(R.string.fight_create_room);
        final EditText etUserName = dialog.findViewById(R.id.et_user_name);
        etUserName.setRawInputType(InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
        etUserName.setFilters(new InputFilter[]{
                (charSequence, i, i1, spanned, i2, i3) -> {
                    if (!Pattern.matches(REGEX_NAME_INPUT, charSequence.toString())) {
                        return "";
                    }
                    return null;
                }
        });
        final EditText etRoomName = dialog.findViewById(R.id.et2);
        etRoomName.setHint(R.string.fight_input_room_name);
        Button btnCancel = dialog.findViewById(R.id.btn_cancel);
        Button btnConfirm = dialog.findViewById(R.id.btn_confirm);
        btnCancel.setOnClickListener(v -> dialog.dismiss());
        btnConfirm.setOnClickListener(v -> {
            String userName = etUserName.getText().toString();
            if (userName.length() < 4 || userName.length() > 20) {
                ToastUtil.toast(R.string.fight_username_error);
                return;
            }
            String roomName = etRoomName.getText().toString();
            if (roomName.length() < 4 || roomName.length() > 20) {
                ToastUtil.toast(R.string.fight_room_name_error);
                return;
            }
            dialog.dismiss();
            if (NativeLibrary.NetPlayCreateRoom(userName, roomName)) {
                DialogUtil.showSingleTip(context, context.getString(R.string.fight_create_room_success, getIpAddressByWifi()));
                netPlayDialog.dismiss();
            } else {
                ToastUtil.toast(R.string.fight_create_room_error);
            }
        });
    }

    /**
     * 弹窗：连接到房间
     */
    private static void showConnectToRoomDialog(final Context context) {
        final AlertDialog dialog = getInstance().connectToRoomDialog = new AlertDialog.Builder(context, R.style.AiWuDialog)
                .setCancelable(true)
                .setView(R.layout.dialog_fight_room)
                .show();
        dialog.setOnDismissListener(dialog1 -> getInstance().connectToRoomDialog = null);

        DialogUtil.setDialog(dialog, 0.45f, 0.0f, 0.75f, 0.0f);

        TextView tvTitle = dialog.findViewById(R.id.tv_title);
        tvTitle.setText(R.string.fight_connect_to_room);
        final EditText etUserName = dialog.findViewById(R.id.et_user_name);
        etUserName.setRawInputType(InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
        etUserName.setFilters(new InputFilter[]{
                (charSequence, i, i1, spanned, i2, i3) -> {
                    if (!Pattern.matches(REGEX_NAME_INPUT, charSequence.toString())) {
                        return "";
                    }
                    return null;
                }
        });
        final EditText etIp = dialog.findViewById(R.id.et2);
        etIp.setHint(R.string.fight_input_room_ip);
        etIp.setFilters(new InputFilter[]{
                (charSequence, i, i1, spanned, i2, i3) -> {
                    if (!Pattern.matches(REGEX_IP_INPUT, charSequence.toString())) {
                        return "";
                    }
                    return null;
                }
        });
        Button btnCancel = dialog.findViewById(R.id.btn_cancel);
        Button btnConfirm = dialog.findViewById(R.id.btn_confirm);
        btnCancel.setOnClickListener(v -> dialog.dismiss());
        btnConfirm.setOnClickListener(v -> {
            String userName = etUserName.getText().toString();
            if (userName.length() < 4 || userName.length() > 20) {
                ToastUtil.toast(R.string.fight_username_error);
                return;
            }
            String ip = etIp.getText().toString();
            if (TextUtils.isEmpty(ip) || !Pattern.matches(REGEX_IP, ip)) {
                ToastUtil.toast(R.string.fight_room_ip_error);
                return;
            }
            getInstance().switchConnectedRoomLoading(true);
            ThreadPoolManager.getInstance().executeTask(() -> {
                NativeLibrary.NetPlayConnectToRoom(userName, ip);
            });
        });
    }

    /**
     * 判断 wifi 是否连接状态
     */
    private static boolean isWifiConnected() {
        ConnectivityManager cm = (ConnectivityManager) CitraApplication.getAppContext().getSystemService(Context.CONNECTIVITY_SERVICE);
        if (cm == null) return false;
        NetworkInfo ni = cm.getActiveNetworkInfo();
        return ni != null && ni.getType() == ConnectivityManager.TYPE_WIFI;
    }

    /**
     * 根据 WiFi 获取网络 IP 地址
     */
    private static String getIpAddressByWifi() {
        @SuppressLint("WifiManagerLeak")
        WifiManager wm = (WifiManager) CitraApplication.getAppContext().getSystemService(Context.WIFI_SERVICE);
        if (wm == null) return "";
        return Formatter.formatIpAddress(wm.getDhcpInfo().ipAddress);
    }
}
